local OperateActivityExcel = require("excel.OperateActivity")
local BaseConfig = OperateActivityExcel.base[1]
local ActivityConfig = OperateActivityExcel.activity
local DateConfig = OperateActivityExcel.date
local ActDefine = require("activity.Define")
local ActHandlerW = require("activity.HandlerW")
local InnerDataManagerFW = require("innerdata.InnerDataManagerFW")
local InnerDataDefine = require("innerdata.Define")
local ServerCommonFW = require("serverCommon.ServerCommonFW")
local ComplexSrvActFW = require("activity.ComplexSrvActFW")
local DB = require("common.DB")
local LuaMongo = _G.lua_mongo
local Config = require("Config")
local Util = require("common.Util")
local PfLogic = require("tencentApi.PfLogic")
local Banshu = require("common.Banshu")

OperateActDataList = OperateActDataList or {}
OperateActList = OperateActList or {}
CallBackList = CallBackList or {}
GMDAY = GMDAY or 0

function onGetOpenDate()
    local nServerOpenTime = ServerCommonFW.getFirstOpenTime()
    local nServerOpenDataTime = os.date("*t", nServerOpenTime)
    local nStartDateTime = {}
    nStartDateTime.year = nServerOpenDataTime.year
    nStartDateTime.month = nServerOpenDataTime.month
    nStartDateTime.day = nServerOpenDataTime.day
    nStartDateTime.hour = 0
    nStartDateTime.min = 0
    nStartDateTime.sec = 0
    return os.time(nStartDateTime)
end

function onGetRoundLen()
    local nLen = 0
    for k, v in ipairs(DateConfig) do
        nLen = nLen + 1
        if v.round[1] == 1 then
            if k <= v.round[2] then
                return 0
            else
                return k - v.round[2]
            end
        end
    end

    if BaseConfig.day1 < #DateConfig then
        return #DateConfig - BaseConfig.day1
    end
    return 0
end

function onGetNextRoundBegin()
    --local nAllDateLen = onGetAllDateLen()
    --if DateConfig[nAllDateLen] and DateConfig[nAllDateLen].round[1] == 1 then
    --    return DateConfig[nAllDateLen].round[2] or 0
    --end
    for k, v in ipairs(DateConfig) do
        if v.round[1] == 1 then
            if k <= v.round[2] then
                return 0
            else
                return v.round[2]
            end
        end
    end

    if BaseConfig.day1 < #DateConfig then
        return BaseConfig.day1 + 1
    end
    return 0
end

function onGetCurRoundAndCurDay(openday, type)
    if openday <= onGetAllDateLen() then
        return 0, openday
    end
    local nRoundLen = onGetRoundLen()
    if nRoundLen <= 0 then
        return 0, openday
    end
    local nDiffDay = openday - BaseConfig.day1
    local nMod = nDiffDay % nRoundLen
    if type == 1 then
        return math.floor(nDiffDay / nRoundLen), (nMod == 0 and 0 or (onGetNextRoundBegin() + nDiffDay % nRoundLen - 1))
    elseif type == 2 then
        return math.floor(nDiffDay / nRoundLen), (nMod == 0 and onGetAllDateLen() or (onGetNextRoundBegin() + nDiffDay % nRoundLen - 1))
    end
end

function onGetAllDateLen()
    return #DateConfig
    --return BaseConfig.day1 + onGetRoundLen()
end

function ctlActList(openday)
    local nTodayActList = {}
    local nTomorrowActList = {}
    local nRoundLen = onGetRoundLen()
    local nAllRound, nCurConfigDay = onGetCurRoundAndCurDay(openday, 1)
    local nOpenDay = openday
    local nTempDay = 1
    local nBegin = 1
    local nAllDateLen = onGetAllDateLen()
    for nRound = 0, nAllRound do
        local nLen = 0
        local nEnd = 0
        if nRound == nAllRound then
            nEnd = (nCurConfigDay <= nAllDateLen and nCurConfigDay or nAllDateLen)
        else
            nEnd = nAllDateLen
        end
        for i = nBegin, nEnd do
            if DateConfig[i] then
                for k, v in ipairs(DateConfig[i].openlist) do
                    local nActConfigID = v[1]
                    local nLastTime = v[3]
                    if nActConfigID ~= ActDefine.OPERATEACT_TYPE_QPOINT and not Banshu.isbstmAct(nActConfigID) 
                        or (nActConfigID == ActDefine.OPERATEACT_TYPE_QPOINT and not PfLogic.isAgentOther()) then
                        if nTempDay + nLastTime > openday 
                            and not nTodayActList[nActConfigID] 
                            and not onCheckActIsRunning(nActConfigID) 
                            and (nActConfigID == ActDefine.OPERATEACT_TYPE_QPOINT and (not PfLogic.isAgentOther()) or true) then
                            nTodayActList[nActConfigID] = v
                            nTodayActList[nActConfigID].startDateTime = onGetOpenDate() + ((nTempDay - 1) * 86400)
                            nTodayActList[nActConfigID].sort = k
                            local nEndDateTime = {}
                            local nTempEndDateTime = os.date("*t", nTodayActList[nActConfigID].startDateTime + ((nLastTime - 1) * 86400))
                            nEndDateTime.year = nTempEndDateTime.year
                            nEndDateTime.month = nTempEndDateTime.month
                            nEndDateTime.day = nTempEndDateTime.day
                            nEndDateTime.hour = 23
                            nEndDateTime.min = 59
                            nEndDateTime.sec = 59
                            nTodayActList[nActConfigID].endDateTime = os.time(nEndDateTime)
                            --if nTempDay + nLastTime > openday + 1 and not nTomorrowActList[nActConfigID] then
                            --    nTomorrowActList[nActConfigID] = v
                            --    nTomorrowActList[nActConfigID].sort = k
                            --    nTomorrowActList[nActConfigID].startDateTime = nTodayActList[nActConfigID].startDateTime
                            --    nTomorrowActList[nActConfigID].endDateTime = nTodayActList[nActConfigID].endDateTime
                            --end
                        end
                    end
                end
            end
            nLen = nLen + 1
            nTempDay = nTempDay + 1
        end
        nOpenDay = nOpenDay - nLen
        nBegin = onGetNextRoundBegin()
        if nBegin == 0 then
            break
        end
        nEnd = (nOpenDay <= nRoundLen and (nBegin + nOpenDay) or nAllDateLen)
    end

    nAllRound, nCurConfigDay = onGetCurRoundAndCurDay(openday + 1, 2)
    if DateConfig[nCurConfigDay] then
        for k, v in ipairs(DateConfig[nCurConfigDay].openlist) do
            local nActConfigID = v[1]
            if nActConfigID ~= ActDefine.OPERATEACT_TYPE_QPOINT and not Banshu.isbstmAct(nActConfigID) 
                or (nActConfigID == ActDefine.OPERATEACT_TYPE_QPOINT and not PfLogic.isAgentOther()) then
                if not nTomorrowActList[nActConfigID] then
                    nTomorrowActList[nActConfigID] = v
                    nTomorrowActList[nActConfigID].startDateTime = onGetOpenDate() + ((nTempDay - 1) * 86400)
                    nTomorrowActList[nActConfigID].sort = k
                    local nEndDateTime = {}
                    local nTempEndDateTime = os.date("*t", nTomorrowActList[nActConfigID].startDateTime + ((v[3] - 1) * 86400))
                    nEndDateTime.year = nTempEndDateTime.year
                    nEndDateTime.month = nTempEndDateTime.month
                    nEndDateTime.day = nTempEndDateTime.day
                    nEndDateTime.hour = 23
                    nEndDateTime.min = 59
                    nEndDateTime.sec = 59
                    nTomorrowActList[nActConfigID].endDateTime = os.time(nEndDateTime)
                end
            end
        end
    end
    return nTodayActList, nTomorrowActList
end

function onActCheck()
    local nOpenDay = ServerCommonFW.getHadOpenDay()
    if nOpenDay <= 0 then
        return
    end

    local nTimeStamp = os.time()
    if OperateActList._today then
        for nActConfigID, v in pairs(OperateActList._today) do
            if v._configList then
                local nStartTimeStamp = v._configList.startDateTime
                local nEndTimeStamp = v._configList.endDateTime
                local nLeftTime = ((nTimeStamp + GMDAY * 86400) >= nStartTimeStamp and (nTimeStamp + GMDAY * 86400) <= nEndTimeStamp) and nEndTimeStamp - (nTimeStamp + GMDAY * 86400) or 0
                if nLeftTime > 0 then
                    if not onProcessAct(nActConfigID, nLeftTime, ActDefine.ACT_STATE_RUNNING, v._configList, 1) then

                    end
                end

                --检查进行中的活动
                if v._running then
                    local nEndTimeStamp = v._running.actArgs.endDateTime
                    if nEndTimeStamp <= (nTimeStamp + GMDAY * 86400) then      --活动到达结束时间
                        --onEndAct(v._running.actnum)
                        onProcessAct(nActConfigID, 0, ActDefine.ACT_STATE_ENDED, v._configList, 1)
                    end
                end
            end
        end
    end

    if OperateActList._tomorrow then
        for nActConfigID, v in pairs(OperateActList._tomorrow) do
            if not onProcessAct(nActConfigID, -1, ActDefine.ACT_STATE_READY, v._configList, 2) then

            end
        end
    end
end

function onProcessAct(actConfigID, gap, actState, actArgs, type)
    local nActConfigData = nil 
    if type == 1 then
        nActConfigData = OperateActList._today[actConfigID]
    elseif type == 2 then
        nActConfigData = OperateActList._tomorrow[actConfigID]
    end

    if not nActConfigData or not gap or not actState then
        return false
    end

    if actState == ActDefine.ACT_STATE_READY then
        onSend2LActUpdate(actConfigID, actState, actArgs, type)
    elseif actState == ActDefine.ACT_STATE_RUNNING then
        if not onCheckActIsRunning(actConfigID) then
            local nActVersionDate = tonumber(onGetActVersion(actConfigID))
            local nStartDate = tonumber(os.date("%Y%m%d", actArgs.startDateTime))
            local nEndDate = tonumber(os.date("%Y%m%d", actArgs.endDateTime))
            if nActVersionDate < nStartDate or nActVersionDate > nEndDate then
                --if onGetActVersion(actConfigID) ~= tonumber(os.date("%Y%m%d")) then
                OperateActDataList[actConfigID] = {}
                OperateActDataList[actConfigID]._data = {}
                onSetActVersion(actConfigID)
                onSetActDBData(actConfigID, OperateActDataList[actConfigID]._data)
            end
            OperateActDataList[actConfigID] = OperateActDataList[actConfigID] or {_data = {}}
            nActConfigData._running = {actConfigID = actConfigID, actArgs = actArgs}
            onCallBack(actConfigID, actState, actArgs)
            onSend2LActUpdate(actConfigID, actState, actArgs, type)
            --ActHandlerW.onSendBroadcast(actConfigID, actState)
            ActHandlerW.onSend2ClientOperateActUpdate(actConfigID, 2, actArgs)
            return true
        else
            if not nActConfigData._running or (nActConfigData._running and nActConfigData._running.actConfigID ~= actConfigID) then
                ActHandlerW.onSend2ClientOperateActUpdate(actConfigID, 2, actArgs)
            end
        end
    elseif actState == ActDefine.ACT_STATE_ENDED then
        if not nActConfigData._endList[actConfigID] then
            nActConfigData._endList[actConfigID] = {}
        end
        onCallBack(actConfigID, actState, actArgs)
        nActConfigData._running = nil
        ActHandlerW.onSend2ClientOperateActUpdate(actConfigID, 2, actArgs)
        onSend2LActUpdate(actConfigID, actState, actArgs, type)
        OperateActDataList[actConfigID]._data = nil
        saveDB(actConfigID, OperateActDataList[actConfigID])
        OperateActList._today[actConfigID] = nil
        --ActHandlerW.onSendBroadcast(actConfigID, actState)
        return true
    end
    return false
end

function onSend2LActUpdate(actConfigID, status, actArgs, type)
    local nSend2Ldata = {
        type = 2,
        data = {
            type = type,
            status = status,
            actConfigID = actConfigID,
            actArgs = actArgs,
        }
    }
    InnerDataManagerFW.Send2LInnerData(nil, InnerDataDefine.INNERDATA_TYPE_ACT, nSend2Ldata)
end

function onGetActStatus(actConfigID, startDateTime, endDateTime)
    if OperateActList._today[actConfigID] and OperateActList._today[actConfigID]._running then
        return ActDefine.ACT_STATE_RUNNING
    else
        local nStartTimeStamp = startDateTime
        local nTimeStamp = os.time()
        if (nTimeStamp + (GMDAY * 86400))  < nStartTimeStamp then
            return ActDefine.ACT_STATE_READY
        else
            return ActDefine.ACT_STATE_ENDED
        end
    end
end

function onGetLeftTime(actConfigID, actArgs, type)
    local nActData = nil

    if type == 1 then
        nActData = OperateActList._today
    elseif type == 2 then
        nActData = OperateActList._tomorrow
    end

    if not nActData then
        return 0
    end

    local nActConfigData = nActData[actConfigID]
    if nActConfigData then
        local nStatus = onGetActStatus(actConfigID, actArgs.startDateTime, actArgs.endDateTime)
        if nStatus == ActDefine.ACT_STATE_READY then
            return 0
        elseif nStatus == ActDefine.ACT_STATE_RUNNING then
            local nEndTimeStamp = actArgs.endDateTime
            local nTimeStamp = os.time()
            local nLeftTime = nEndTimeStamp - nTimeStamp - (GMDAY * 86400)
            return nLeftTime <= 0 and 0 or nLeftTime
        else
            return 0
        end
    end
end

function onGetCurActRuleID(actConfigID)
    if OperateActList._today and OperateActList._today[actConfigID] and OperateActList._today[actConfigID]._running then
        return OperateActList._today[actConfigID]._running.actArgs.ruleid
    end
end

function onGetTomorrowActRuleID(actConfigID)
    if OperateActList._tomorrow and OperateActList._tomorrow[actConfigID] and OperateActList._tomorrow[actConfigID]._configList then
        return OperateActList._tomorrow[actConfigID]._configList.ruleid
    end
end

function onCheckActIsRunning(actConfigID)
    if OperateActList._today and OperateActList._today[actConfigID] and OperateActList._today[actConfigID]._running then
        return true
    end
end

function onDayChange(day1)
    GMDAY = day1
    onInitTodayAct()
    onActCheck()
end

function onRegisterCallBack(actConfigID, onBeginBefore, onRunning, onEnd, actArgs)
    CallBackList[actConfigID] = {[ActDefine.ACT_STATE_BEFORESTART] = onBeginBefore, [ActDefine.ACT_STATE_RUNNING] = onRunning, [ActDefine.ACT_STATE_ENDED] = onEnd, args = actArgs}
end

function onCallBack(actConfigID, status, actArgs)
    local nCallBackData = CallBackList[actConfigID]
    if nCallBackData and nCallBackData[status] then
        nCallBackData[status](actConfigID, actArgs, nCallBackData.args)
    end
end

function onSetActVersion(actConfigID)
    OperateActDataList[actConfigID].version = tonumber(os.date("%Y%m%d"))
    OperateActList._today[actConfigID]._configList.version = OperateActDataList[actConfigID].version
end

function onGetActVersion(actConfigID)
    if not OperateActDataList[actConfigID] or not OperateActDataList[actConfigID].version then
        return 0
    end
    return OperateActDataList[actConfigID].version
end

function onInitTodayAct(mustEnd)
    if Config.IS_MIDDLE then
        return
    end

    local nTimeStamp = os.time()

    --检查今天进行中的活动, 如果有要结束的这里要统一结束
    if OperateActList._today then
        for nActConfigID, nActData in pairs(OperateActList._today) do
            if nActData._running then
                --onEndAct(v._running.actnum)
                local nEndTimeStamp = nActData._running.actArgs.endDateTime
                if mustEnd or nEndTimeStamp <= (nTimeStamp + GMDAY * 86400) then      --活动到达结束时间
                    onProcessAct(nActConfigID, 0, ActDefine.ACT_STATE_ENDED, nActData, 1)
                end
            end
        end
    end

    if ComplexSrvActFW.hasComplexSrvAct() then
        return
    end

    OperateActList._today = OperateActList._today or {}
    OperateActList._tomorrow = {}
    --如果服务器已开启时间小于等于0则不跑活动
    local nOpenDay = ServerCommonFW.getHadOpenDay()
    if nOpenDay <= 0 then
        return
    end

    --开始初始化今日活动列表，初始化完后OperateActList中将保存所有有效的活动，有之前与今日的
    local nTodayActList, nTomorrowActList = ctlActList(nOpenDay)
    if nTodayActList then
        for nActConfigID, nActArgs in pairs(nTodayActList) do
            local nActRuleID = nActArgs[2]
            local nActConfigExcel = ActivityConfig[nActConfigID].actNum
            local nActRuleData = OperateActivityExcel[nActConfigExcel][nActRuleID]
            if nActRuleData then
                if not OperateActList._today[nActConfigID] or OperateActList._today[nActConfigID]._running == nil then
                    if not OperateActList._today[nActConfigID] then
                        OperateActList._today[nActConfigID] = {
                            _beginbefore = nil,             --预告中的活动
                            _running = nil,                 --运行中的活动
                            _endList = {},
                        }
                    end

                    local nStartTimeStamp = nActArgs.startDateTime
                    local nEndTimeStamp = nActArgs.endDateTime
                    OperateActList._today[nActConfigID]._configList = nil
                    OperateActList._today[nActConfigID]._configList = {_configID = nActConfigID, version = onGetActVersion(nActConfigID), startDateTime = nStartTimeStamp, endDateTime = nEndTimeStamp, ruleid = nActRuleID, iconid = nActArgs[4], effectid = nActArgs[5], modletype = nActArgs[7], modleid = nActArgs[6], sort = nActArgs.sort}
                end
            end
        end
    end

    if nTomorrowActList then
        for nActConfigID, nActArgs in pairs(nTomorrowActList) do
            local nActRuleID = nActArgs[2]
            local nActConfigExcel = ActivityConfig[nActConfigID].actNum
            local nActRuleData = OperateActivityExcel[nActConfigExcel][nActRuleID]
            if nActRuleData then
                if not OperateActList._tomorrow[nActConfigID] then
                    OperateActList._tomorrow[nActConfigID] = {
                        _beginbefore = nil,             --预告中的活动
                        _running = nil,                 --运行中的活动
                        _endList = {},
                    }
                end

                local nStartTimeStamp = nActArgs.startDateTime
                local nEndTimeStamp = nActArgs.endDateTime
                OperateActList._tomorrow[nActConfigID]._configList = nil
                OperateActList._tomorrow[nActConfigID]._configList = {_configID = nActConfigID, startDateTime = nStartTimeStamp, endDateTime = nEndTimeStamp, ruleid = nActRuleID, iconid = nActArgs[4], effectid = nActArgs[5], modletype = nActArgs[7], modleid = nActArgs[6], sort = nActArgs.sort}
            end
        end
    end
end

function onGetTodayActList()
    return OperateActList._today
end

function onGetTomorrowActList()
    return OperateActList._tomorrow
end

function onGetActDesc(actConfigID, actRuleID)
    local nActConfigExcel = ActivityConfig[actConfigID].actNum
    if nActConfigExcel then
        local nActRuleData = OperateActivityExcel[nActConfigExcel][actRuleID]
        if nActRuleData then
            return nActRuleData.desc or ""
        end
    end
end

function onSetActDBData(actConfigID, actData)
    OperateActDataList[actConfigID] = OperateActDataList[actConfigID] or {_data = {}} 
    OperateActDataList[actConfigID]._data = actData
    OperateActDataList[actConfigID].version = onGetActVersion(actConfigID)
    OperateActDataList[actConfigID].actConfigID = actConfigID
    saveDB(actConfigID, OperateActDataList[actConfigID])
end

function onGetActDBData(actConfigID)
    return OperateActDataList[actConfigID] and OperateActDataList[actConfigID]._data or nil
end

function saveDB(actConfigID, actData)
    LuaMongo.update(DB.db_operateact, {actConfigID = actConfigID}, actData, true)
end

initStatus = initStatus or false
function onInit(clear, day1, day2)
    if initStatus == false or clear then
        --if clear then
        --    for nType, v in pairs(OperateActList) do
        --        for nActConfigID, nActData in pairs(v._configList) do
        --            for nActNum, nActArgs in pairs(nActData) do
        --                onProcessAct(nType, nActConfigID, nActNum, 0, ActDefine.ACT_STATE_ENDED, nActArgs)
        --            end
        --        end
        --        OperateActList[nType] = nil
        --    end
        --end
        --initStatus = true
    end
    LuaMongo.find(DB.db_operateact)
    while true do
        local nReader = {}
        if not LuaMongo.next(nReader) then
            break
        end

        local actConfigID = nReader.actConfigID
        if actConfigID then
            OperateActDataList[actConfigID] = {} 
            OperateActDataList[actConfigID]._data = nReader._data
            OperateActDataList[actConfigID].version = nReader.version or 0 
            OperateActDataList[actConfigID].actConfigID = actConfigID
        end
    end
end

onInit()
